#!/usr/bin/env bash
###################################################################
# Function :安装yum源                                              #
# Platform :RedHatEL7.x Based Platform                            #
# Version  :1.0                                                   #
# Date     :2021-07-17                                            #
# Author   :houxiaoshuai@baidu.com & hxsaj@126.com                #
###################################################################
set -e

#  变量列表 Variable list
########## ########## ########## ########## ########## ########## #
#  默认 ISO 挂载目录
DEFAULT_MOUNT_DIR=/opt/iso_packages
#  默认 IOS 文件存放位置
DEFAULT_IOS_F_DIR=/opt/iso_files
#  默认生成的本地 repo 文件
DEFAULT_REPO_FILE=/etc/yum.repos.d/base_iso.repo
#  默认生成的基于 http 的 repo 文件
DEFAULT_REPO_HTTP=base_http_iso.repo

#  函数列表 Function list
########## ########## ########## ########## ########## ########## #
info_p(){  printf "\e[1;32;40m%-12s %-1s\n\e[0m" "${1}" "${2}"  >&1 ;}
tips_p(){  printf "\e[1;36;40m%-12s %-1s\n\e[0m" "${1}" "${2}"  >&1 ;}
error_p(){ printf "\e[1;35;40m%-12s %-1s\n\e[0m" "${1}" "${2}"  >&1 ;}

#  获取本机 IP 地址
get_host_ip() {
    ip a | grep -w inet | grep -v docker | grep -w global | awk -F "/" '{print $1}' | awk '{print $2}'
}
#  帮助说明
help_f(){
    echo -e "说明：\n    实现交互友好挂载iso镜像部署本地yum源（支持加选项一键挂载）"
    echo -e "\n可用的选项如下（不带选项将进入交互模式）："
    echo -e "    -h or --help    帮助说明"
    echo -e "    -i or --image   指定 iso 文件，后面需空格紧跟 ISO 镜像文件"
    echo -e "    -d or --dir     指定挂载目录（如不指定，将会使用默认的挂载位置 /opt/iso_packages)，后面需空格紧跟挂载的目录"
    echo -e "    -r or --release 发布基于http的yum源，后跟本机IP地址 既本机挂载iso文件后部署生成基于http的源文件，其他可达服务器使用此文件即可使用此yum源，默认生成的repo文件存放于执行脚本的目录下"
}
function change_opera(){
    echo -e "\n操作内容："
    tips_p "1） 挂载 ISO 镜像部署本地"
    tips_p "2） 卸载 ISO 镜像本地源"
    tips_p "3） 发布 ISO 镜像源到 HTTP 服务"
    tips_p "4） 关闭 ISO 镜像源到 HTTP 服务"
    tips_p "5） 查看帮助"
    tips_p "q） 退出\n"
    read -p "选择（输入序号）：" ch_op
    case C${ch_op} in
        C1 ) install_yum_iso;   change_opera  ;;
        C2 ) uninstall_yum_iso; change_opera  ;;
        C3 ) release_http_yum;  change_opera  ;;
        C4 ) unrelease_http_yum;change_opera  ;;
        C5 ) help_f;            change_opera  ;;
        Cq ) exit                             ;;
        C* ) change_opera                     ;;
    esac
}
#  镜像挂载，参数2：[ iso文件 ] [ iso挂载位置 ]
function install_yum_iso() {
    # 检测 iso 文件 [ iso文件 ]
    get_iso_file(){
        if [[ $# -eq 0 ]];then
            read -p  "输入 ISO 文件：" ISO_PATH
            #  检查文件
            if [[ -z ${ISO_PATH} ]];then
                get_iso_file
            elif [[ ! -e ${ISO_PATH} ]] || [[ $(file -b ${ISO_PATH} | grep -w ISO | wc -l) -ne 1 ]];then
                error_p "[ ERROR   ]: ${ISO_PATH} 不存在或不是ISO文件"
                get_iso_file
            else
                export ISO_PATH=${ISO_PATH}
            fi
        elif [[ $# -eq 1 ]]; then
            ISO_PATH=${1}
            #  检查文件
            if [[ ! -e ${ISO_PATH} ]] || [[ $(file -b ${ISO_PATH} | grep -w ISO | wc -l) -ne 1 ]];then
                error_p "[ ERROR   ]: ${1} 不存在或不是ISO文件"
                return 1
            else
                export ISO_PATH=${1}
            fi
        else
            error_p "[ ERROR   ] 仅支持参数个数为 0 或 1 个！"
        fi
    }
    get_mount_dir(){
        if [[ $# -eq 0 ]];then
            read -p  "挂载目录(不存在则新建)：" MOUNT_DIR
            #  检查目录
            if [[ -z ${MOUNT_DIR} ]];then
                get_mount_dir
            elif [[ -d ${MOUNT_DIR} ]] && [[ $(df -hT | grep -e ${MOUNT_DIR} | grep iso9660) -eq 1 ]]; then
                error_p "[ FAILED  ]: ${MOUNT_DIR} 目录已经被挂载占用"
                get_mount_dir
            elif [[ -d ${MOUNT_DIR} ]] && [[ $(ls -A ${MOUNT_DIR} | wc -w) -gt 0 ]]; then
                error_p "[ FAILED  ]: ${MOUNT_DIR} 目录不为空"
                get_mount_dir
            elif [[ -d ${MOUNT_DIR} ]] && [[ $(ls -A ${MOUNT_DIR} | wc -w) -eq 0 ]]; then
                export MOUNT_DIR=${MOUNT_DIR}
            elif [[ ! -d ${MOUNT_DIR} ]]; then
                mkdir -p ${MOUNT_DIR}
                export MOUNT_DIR=${MOUNT_DIR}
            fi
        elif [[ $# -eq 1 ]]; then
            #  检查目录
            if [[ ! -e ${1} ]];then
                mkdir -p ${1}
                export MOUNT_DIR=${1}
            elif [[ -d ${1} ]] && [[ $(df -hT | grep -e ${1} | grep iso9660 |wc -l) -eq 1 ]]; then
                error_p "[ FAILED  ]: ${1} 目录已经被挂载占用"
                return 1
            elif [[ -d ${1} ]] && [[ $(ls -A ${1} | wc -w) -gt 0 ]]; then
                error_p "[ FAILED  ]: ${1} 目录不为空"
                return 1
            elif [[ -d ${1} ]] && [[ $(ls -A ${1} | wc -w) -eq 0 ]]; then
                export MOUNT_DIR=${1}
            elif [[ ! -d ${1} ]]; then
                error_p "[ ERROR   ]: ${1} 不是目录，请检查"
                return 1
            fi
        else
            error_p "[ ERROR   ] 仅支持参数个数为 0 或 1 个！"
        fi
    }
    create_repo_iso(){
        REPO_FILE=${DEFAULT_REPO_FILE}
        #  备份同名yum源文件
        if [[ -f ${REPO_FILE} ]];then
            cp -a ${REPO_FILE}{,.$(date +%Y-%m-%d_%H%M%S)}
        fi
        #  检查参数
        if [[ -z ${REPO_FILE} ]] || [[ -z ${MOUNT_DIR} ]];then
            error_p "[ FAILED  ]: 参数 ${REPO_FILE} 或 ${MOUNT_DIR} 为空"
            return 1
        fi
        #  生成 repo 文件
        if [[ $(df -T | grep ${MOUNT_DIR} | grep iso9660 | wc -l) -eq 1 ]]; then
            echo -e "[iso]"                        > ${REPO_FILE}
            echo -e "name=iso"                    >> ${REPO_FILE}
            echo -e "baseurl=file://${MOUNT_DIR}" >> ${REPO_FILE}
            echo -e "enabled=1"                   >> ${REPO_FILE}
            echo -e "gpgcheck=0"                  >> ${REPO_FILE}
            if [[ -f ${REPO_FILE} ]];then
                info_p  "[ SUCCESS ]: ${REPO_FILE} 文件创建成功"
            else
                error_p "[ FAILED  ]: ${REPO_FILE} 文件创建失败"
            fi
        fi
    }
    mount_iso(){
        if [[ $# -ne 2 ]];then
            ISO_FILE=${1}
            MOUNT_DIR=${2}
            #  获取文件绝对路径
            ISO_PATH=$(readlink -f ${ISO_FILE})
            #  检查文件
            if [[ ! -e ${ISO_PATH} ]];then
                error_p "[ ERROR   ]: ${ISO_PATH} 文件不存在"
                return 1
            elif [[ X"$(file -b ${ISO_PATH} |grep -wo ISO)" != X"ISO" ]];then
                error_p "[ ERROR   ]: ${ISO_PATH} 不是ISO文件"
                return 1
            elif [[ $(df -T | grep -i iso9660 |wc -l) -gt 0 ]]; then
                error_p "[ FAILED  ]: 系统已存在 ISO 挂载，挂载目录: $(df -T | grep -i iso9660 |awk '{print$NF}')，请卸载后重试"
                return 1
            fi
            #  检查目录
            if [ -d ${MOUNT_DIR} ];then
                if df -hT | grep -e ${MOUNT_DIR} | grep iso9660 >/dev/null 2>&1; then
                    error_p "[ FAILED  ]: ${MOUNT_DIR} 目录已经被挂载占用"
                    return 2
                elif [ $(ls -A ${MOUNT_DIR} | wc -w) -eq 0 ]; then
                    mount -t iso9660 ${ISO_PATH} ${MOUNT_DIR} >/dev/null 2>&1
                    info_p  "[ SUCCESS ]: ${MOUNT_DIR} 挂载成功"
                else
                    error_p "[ FAILED  ]: ${MOUNT_DIR} 挂载点不为空"
                fi
            else
                mkdir -p ${MOUNT_DIR}
                if mount -t iso9660 ${ISO_PATH} ${MOUNT_DIR} >/dev/null 2>&1;then
                    info_p  "[ SUCCESS ]: ${MOUNT_DIR} 挂载成功"
                else
                    error_p "[ FAILED  ]: ${MOUNT_DIR} 挂载失败"
                fi
            fi
        else
            get_iso_file
            get_mount_dir
            mount_iso ${ISO_FILE} ${MOUNT_DIR}
        fi
    }
    #  主程序
    if [[ $# -eq 0 ]];then
        get_iso_file
        get_mount_dir
        if mount -t iso9660 ${ISO_PATH} ${MOUNT_DIR} >/dev/null 2>&1;then
            info_p  "[ SUCCESS ]: mount ${ISO_FILE} ${MOUNT_DIR} 挂载成功"
            create_repo_iso
        else
            error_p "[ FAILED  ]: mount ${ISO_FILE} ${MOUNT_DIR} 挂载失败"
            return 1
        fi
    elif [[ $# -eq 2 ]]; then
        get_iso_file ${1}
        get_mount_dir ${2}
        if mount -t iso9660 ${ISO_PATH} ${MOUNT_DIR} >/dev/null 2>&1;then
            info_p  "[ SUCCESS ]: mount ${1} ${2} 挂载成功"
            create_repo_iso
        else
            error_p "[ FAILED  ]: mount ${1} ${2} 挂载失败"
            return 1
        fi
    else
        error_p "[ ERROR   ] 仅支持参数个数为 0 或 2 个！[ iso_file ] [ mount_dir ]"
    fi
}
#  镜像卸载，参数1：[ iso挂载位置 ]
function uninstall_yum_iso(){
    #  获取本机挂载镜像的目录
    get_type_iso_dir(){
        TYPE_ISO_DIRS=($(df -T | awk '/iso9660/{print$NF}'))
        if [[ $# -eq 0 ]];then
            if [[ ${#TYPE_ISO_DIRS[@]} -gt 1 ]];then
                echo -e "系统存在多个ISO镜像挂载目录:"
                echo ${TYPE_ISO_DIRS[@]} | tr " " "\n" |awk '$0=" "NR") "$0'
                read -p "选择卸载的目标目录：" C_ISO_REDIR
                if seq 1 ${#TYPE_ISO_DIRS[@]} | grep -q  ${C_ISO_REDIR};then
                    export MOUNT_DIR=${TYPE_ISO_DIRS[$(expr ${C_ISO_REDIR} - 1)]}
                else
                    error_p "[ ERROR   ] 选择范围错误"
                    get_type_iso_dir
                fi
            else
                export MOUNT_DIR=${TYPE_ISO_DIRS[0]}
            fi
        elif [[ $# -eq 1 ]]; then
            if echo ${TYPE_ISO_DIRS[@]} | grep -qw ${1};then
                export MOUNT_DIR=${1}
            else
                error_p "[ ERROR   ] ${1} 系统中不存在或非ISO挂载目录"
                export MOUNT_DIR=
                return 1
            fi
        else
            error_p "[ ERROR   ] $0 [ iso_mount_dir ]"
        fi
    }
    #  删除 repo 文件
    delete_repo_file(){
        unset REPO_FILES
        if [[ -n ${MOUNT_DIR} ]];then
            REPO_FILES=($(grep -lrsw $(basename ${MOUNT_DIR}) /etc/yum.repos.d/))
            for i in ${REPO_FILES[@]};do
                if rm -f ${i};then
                    info_p  "[ SUCCESS ]: ${i} repo文件删除成功"
                else
                    error_p "[ ERROR   ]: ${i} repo文件删除失败"
                fi
            done
        else
            error_p "[ ERROR   ]: 挂载目录：${MOUNT_DIR} 未获取到，未删除文件"
        fi
    }
    #  卸载挂载目录
    umount_type_iso_dir(){
        if [[ -n ${MOUNT_DIR} ]];then
            umount ${MOUNT_DIR}
            if ! df -T | awk '/iso9660/{print$NF}' | grep -qw "${MOUNT_DIR}";then
                info_p  "[ SUCCESS ]: ${MOUNT_DIR} 卸载成功"
            else
                error_p "[ ERROR   ]: ${MOUNT_DIR} 卸载失败"
            fi
        else
            error_p "[ ERROR   ]: 挂载目录：${MOUNT_DIR} 未获取到，未卸载目录"
        fi
    }
    #  主程序
    if [[ $# -eq 0 ]];then
        get_type_iso_dir
        umount_type_iso_dir
        delete_repo_file
    else
        get_type_iso_dir ${1}
        umount_type_iso_dir
        delete_repo_file
    fi
}
#  基于http的yum源 [ ip ] [ iso挂载位置 ]
function release_http_yum() {
    #  获取本机IP
    get_host_ip(){
        # 获取本机IP
        IPS=($(ip a | grep -w inet | grep -v docker | grep -w global | awk -F "/" '{print $1}' | awk '{print $2}'))
        if [[ $# -eq 0 ]];then
            if [[ ${#IPS[@]} -gt 1 ]];then
                echo -e "系统存在的IP:"
                echo ${IPS[@]} | tr " " "\n" |awk '$0=" "NR") "$0'
                read -p "选择发布的IP：" C_IP
                if seq 1 ${#IPS[@]}| grep -q ${C_IP};then
                    export YUM_IP=${IPS[$(expr ${C_IP} - 1)]}
                else
                    error_p "[ ERROR   ] 选择范围错误"
                    get_host_ip
                fi
            else
                export YUM_IP=${IPS[0]}
            fi

        elif [ $# -eq 1 ];then
            if echo ${IPS[@]} | grep -qw ${1};then
                YUM_IP=${1}
            else
                error_p "[ ERROR   ] ${1} 系统中不存在"
                export YUM_IP=
                return 1
            fi
        else
            error_p "[ ERROR   ] $0 [ ip ]"
        fi
    }
    #  获取本机挂载镜像的目录
    get_type_iso_dir(){
        TYPE_ISO_DIRS=($(df -T | awk '/iso9660/{print$NF}'))
        if [[ $# -eq 0 ]];then
            if [[ ${#TYPE_ISO_DIRS[@]} -gt 1 ]];then
                echo -e "系统存在多个ISO镜像挂载目录:"
                echo ${TYPE_ISO_DIRS[@]} | tr " " "\n" |awk '$0=" "NR") "$0'
                read -p "选择发布的目标目录：" C_ISO_REDIR
                if seq 1 ${#TYPE_ISO_DIRS[@]} | grep -q  ${C_ISO_REDIR};then
                    export MOUNT_DIR=${TYPE_ISO_DIRS[$(expr ${C_ISO_REDIR} - 1)]}
                else
                    error_p "[ ERROR   ] 选择范围错误"
                    get_type_iso_dir
                fi
            else
                export MOUNT_DIR=${TYPE_ISO_DIRS[0]}
            fi
        elif [[ $# -eq 1 ]]; then
            if echo ${TYPE_ISO_DIRS[@]} | grep -qw ${1};then
                export MOUNT_DIR=${1}
            else
                error_p "[ ERROR   ] ${1} 系统中不存在或非ISO挂载目录"
                export MOUNT_DIR=
                return 1
            fi
        else
            error_p "[ ERROR   ] $0 [ iso_mount_dir ]"
        fi
    }
    #  检查 httpd 安装情况
    check_httpd_status(){
        #  安装http
        if [ $(systemctl list-unit-files | grep -w httpd| wc -l) -eq 0 ];then
            if yum install httpd -y >/dev/null 2>&1;then
                info_p  "[ SUCCESS ]: httpd 服务安装成功"
                systemctl restart httpd
            else
                error_p "[ ERROR   ] yum 安装 httpd 失败，本地 yum 异常，请检查！"
            fi
        else
            systemctl restart httpd
        fi
    }
    create_http_repo(){
        repo_h(){
            echo -e "[iso_http]"                             >./${DEFAULT_REPO_HTTP}
            echo -e "name=iso_http"                         >>./${DEFAULT_REPO_HTTP}
            echo -e "baseurl=http://${YUM_IP}${MOUNT_DIR}"  >>./${DEFAULT_REPO_HTTP}
            echo -e "enabled=1"                             >>./${DEFAULT_REPO_HTTP}
            echo -e "gpgcheck=0"                            >>./${DEFAULT_REPO_HTTP}
            if [[ -f ./${DEFAULT_REPO_HTTP} ]];then
                info_p  "[ SUCCESS ]: ${DEFAULT_REPO_HTTP} 文件创建成功，复制到网络可达的客户端服务器 /etc/yum.repos.d/下 即可使用本 yum 源服务"
            else
                error_p "[ FAILED  ]: ${DEFAULT_REPO_HTTP} 文件创建失败"
            fi
        }
        if [[ -n ${YUM_IP} ]] && [[ -d ${MOUNT_DIR} ]];then
            #  检查软连接
            if [[ -L /var/www/html/$(basename ${MOUNT_DIR}) ]] && [[ -e /var/www/html/$(basename ${MOUNT_DIR})/repodata/repomd.xml ]];then
                repo_h
            else
                if ln -s ${MOUNT_DIR} /var/www/html/$(basename ${MOUNT_DIR}) ;then
                    info_p  "[ SUCCESS ]: /var/www/html/$(basename ${MOUNT_DIR}) 软连接创建成功"
                    repo_h
                else
                    error_p "[ FAILED  ]: /var/www/html/$(basename ${MOUNT_DIR}) 软连接创建失败"
                    error_p "[ FAILED  ]: ${DEFAULT_REPO_HTTP} repo文件不创建"
                fi
            fi
        else
            echo "[ ERROR   ] ip=${YUM_IP} 或 MOUNT_DIR=${MOUNT_DIR} 未获取"
            return 1
        fi
    }
    if [[ $# -eq 1 ]];then
        YUM_IP=${1}
        get_host_ip ${YUM_IP}
        get_type_iso_dir
        check_httpd_status
        create_http_repo

    elif [[ $# -eq 2 ]];then
        YUM_IP=${1}
        MOUNT_DIR=${2}
        get_host_ip ${YUM_IP}
        get_type_iso_dir ${MOUNT_DIR}
        check_httpd_status
        create_http_repo

    else
        get_host_ip
        get_type_iso_dir
        check_httpd_status
        create_http_repo
    fi
}
#  关闭基于http的源
function unrelease_http_yum(){
    unset ALIAS_DIRS
    #  获取镜像挂载的链接文件数组
    for i in $(find /var/www/html/ -type l);do
        if [[ -e ${i}/repodata/repomd.xml ]];then
            ALIAS_DIRS[${#ALIAS_DIRS[@]}]=${i}
        fi
    done
    #  检查并删除软链接
    if [[ ${#ALIAS_DIRS[@]} -gt 0 ]];then
        for i in ${ALIAS_DIRS[@]};do
            if [[ -e ${i}/repodata/repomd.xml ]];then
                YUM_NAME=$(basename ${i})
                if rm -f ${i};then
                    info_p  "[ SUCCESS ]: ${i} 删除成功，基于本机http://{IP}/${YUM_NAME}源分发关闭"
                else
                    error_p "[ ERROR   ]: ${i} 删除失败，基于本机http://{IP}/${YUM_NAME}源分发未关闭"
                fi
            fi
        done
    else
        info_p  "[ INFO    ]: 未发现基于本机 http 的源分发"
    fi
}


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
# 如果参数为空，则退出
if [ $# -eq 0 ];then
    change_opera
else
    #  获取选项
    while [ -n "$1" ]; do
        case $1 in
            -d | --dir     )
                MOUNT_DIR="${2}"
                shift 2
                ;;
            -r | --release )
                YUM_IP="${2}"
                shift 2
                ;;
            -i | --image )
                ISO_FILE="${2}"
                shift 2
                ;;
            -h | --help )
                help_f
                exit
                ;;
            *)
                break
                ;;
        esac
    done
    #  部署本地ios 源
    if [[ -n ${MOUNT_DIR} ]] && [[ -n ${ISO_FILE} ]];then
        #  获取主机名列表
        install_yum_iso "${ISO_FILE}" "${MOUNT_DIR}"
    elif ([[ -n ${MOUNT_DIR} ]] || [[ -z ${ISO_FILE} ]]) || ([[ -z ${MOUNT_DIR} ]] || [[ -n ${ISO_FILE} ]]);then
        info_p  "[ TIPS    ]: -d 选项与 -i 互相依赖"
        exit 1
    fi
    #  检查发布 http 源
    if [[ -n ${YUM_IP} ]] && [[ -z ${MOUNT_DIR} ]];then
        release_http_yum "${YUM_IP}"
    elif [[ -n ${YUM_IP} ]] && [[ -n ${MOUNT_DIR} ]]; then
        release_http_yum "${YUM_IP}" "${MOUNT_DIR}"
    fi

fi







